package simplex

import scala.util.parsing.combinator._
import scala.util.matching.Regex
import scala.util.parsing.combinator._

/**
 * Parser de las ecuaciones de la aplicacion. 
 * Tiene un object para poder ejecutar este archivo en pruebas.
 * 
 * @author age, joaquinmonleon
 *
 */
class ParserEcuacion extends JavaTokenParsers {   
  
  var debug = true
  
  var Objetivo: Array[Racional] = null
  var Independientes: Array[Racional] = null
  var Datos: Array[Array[Racional]] = null
  var NRest: Int = 0
  var NVars: Int = 0
  var Signo: Int = 1
  var MaxMin: Boolean = true
  var VarObj: String = "z"
  
  // Info para el parseado
  private var minx = Integer.MAX_VALUE
  private var maxx = Integer.MIN_VALUE
  private var m = Matrix.getEmptyMatrix(1, 1)
  private var indep = Matrix.getEmptyMatrix(1, 1)
  private var row = 0

  // Reglas y tokens
  private def ecua: Parser[Any] = obje ~ "in" ~ rep ( expr )
  
  private def obje: Parser[Any] = opt ( sign ) ~ maxmin ~ varobj ~ "=" ~ initerm ~ rep( term ) ^^ {case _ => m = m.redim(m.nRows+1, m.nCols); row+=1; }

  private def sign: Parser[Any] = ( "+" ^^ { case s => Signo = 1} | "-" ^^ { case s => Signo = -1} ) 
  private def maxmin: Parser[Any] = ("Max"  ^^ { case s => MaxMin = true} | "Min"  ^^ { case s => MaxMin = false} )
  private def varobj: Parser[Any] = """[a-zA-Z]+""".r ^^ { case s => VarObj = s}
  
  private def expr: Parser[Any] = initerm ~ rep( term ) ~ "=" ~ coef ^^ {case _~c =>  indep.elements(0)(indep.nCols-1) = c; indep = indep.redim(indep.nRows, indep.nCols+1); m = m.redim(m.nRows+1, m.nCols); row+=1; }
  private def initerm: Parser[Any] = ( coef ~ "x" ~ wholeNumber ^^ {case c~s~n => if (n.toInt < minx) { minx = n.toInt }; if (n.toInt > maxx) { maxx = n.toInt }; if (n.toInt >= m.nCols) {m = m.redim(m.nRows, n.toInt+1)}; m.elements(row)(n.toInt) = c} | "x" ~ wholeNumber ^^ {case s~n => if (n.toInt < minx) { minx = n.toInt }; if (n.toInt > maxx) { maxx = n.toInt }; if (n.toInt >= m.nCols) {m = m.redim(m.nRows, n.toInt+1)}; m.elements(row)(n.toInt) = 1.0; } ) 
  private def term: Parser[Any] = coef ~ "x" ~ wholeNumber ^^ {case c~s~n => if (n.toInt < minx) { minx = n.toInt }; if (n.toInt > maxx) { maxx = n.toInt }; if (n.toInt >= m.nCols) {m = m.redim(m.nRows, n.toInt+1)}; m.elements(row)(n.toInt) = c}
  private def coef: Parser[Double] = ( floatingPointNumber ^^ {case f => f.toDouble*1.0}  | "+" ~ floatingPointNumber ^^ {case s~f => f.toDouble*1.0} | "-" ~ floatingPointNumber ^^ {case s~f => -f.toDouble} | "+" ^^ {case s => 1.0} | "-" ^^ {case s => -1.0} )
  
  def parse (text: String): Simplex = {
    val result = parseAll(ecua, text)
    
    result match {
      case Success(order, _) => None
      case Failure(msg, _) => println("--- Fallo del parser ---\n" + msg); return null;
      case Error(msg, _) => println("--- Error del parser ---\n" + msg); return null;
    }
    
    // Preparar toda la información parseada
    indep.removeCol(indep.nCols-1)
    m.removeRow(m.nRows-1)
    if (minx > 0) {
      m.removeCol(0)
    }
    Objetivo = m.removeRow(0)
    Independientes = indep.elements(0)
    Datos = m.elements    
    NRest = m.nRows
    NVars = m.nCols
    
    if (debug) {
	  println ("--- Información parseada ---")
	  println ("Objetivo: " + Objetivo.deepToString())
	  println ("Independientes: " + Independientes.deepToString())    
	  println ("Datos: " + Datos.deepToString())    
	  println ("Nº Restric: " + NRest)
	  println ("Nº Variables: " + NVars)
	  println ("Signo: " + Signo)
	  println ("MaxMin: " + MaxMin)
	  println ("Variable Objetivo: " + VarObj)
	  println ()
    }
    
    new Simplex(Signo, MaxMin, VarObj, Objetivo, Independientes, NVars, NRest, Datos)
  }
}

object ParserEcuacion {
  def main(args: Array[String]) {
    var pe = new ParserEcuacion()
    pe.parse(" -  Max z = - x1 in - 1x1 +  2 x2 + 3x3 + 4x4 + 5x5 = 3 1 x 1 = 5")
  }
}
